import {EChartOption} from "echarts";
import {copyOpt} from "./base";
import {AxisInfo} from "../class/AxisInfo";
import {NEChartsRelate} from "../declare/base";

export type TOriginAxisType = "" | "Array" | "Object";

export function unifyAndFillAxisInOption(opt: EChartOption, splitNumber?: number) {
    const copiedOpt = copyOpt(opt);
    let axisList: AxisInfo[] = [];
    let originAxisType: TOriginAxisType = "";
    if (copiedOpt.yAxis) {
        const yAxis = copiedOpt.yAxis;
        if (!(yAxis instanceof Array)) {
            originAxisType = "Object";
            axisList = [ new AxisInfo(yAxis) ];
        } else {
            axisList = yAxis.map((item) => {
                return new AxisInfo(item);
            });
            originAxisType = "Array";
        }
    }
    copiedOpt.series?.forEach((seriesItem) => {
       if (seriesItem.type === "line" || seriesItem.type === "bar") {
            const yAxisIndex = parseInt((seriesItem as any).yAxisIndex as string) || 0;
            const yAxisItem = axisList[yAxisIndex];
            if (
                yAxisItem &&
                yAxisItem.isValueAxis() &&
                yAxisItem.isShow() &&
                (seriesItem.data instanceof Array) &&
                !yAxisItem.isHavingOriginRange
            ) {
                yAxisItem.setRangeFromDataList((seriesItem as any).data, (seriesItem as any).stack);
            }
       }
    });
    if (originAxisType === "Object") {
        const singleAxisInfo = axisList[0];
        const singleAxisBaseRange = singleAxisInfo.getBaseRange();
        if (
            singleAxisInfo.hasUpdateRange() &&
            isNaN(singleAxisBaseRange.min) &&
            isNaN(singleAxisBaseRange.max)
        ) {
            const yAxis = (copiedOpt.yAxis as EChartOption.YAxis);
            yAxis.min = 0;
            yAxis.max = 1;
            return yAxis;
        }
    }
    let list = copiedOpt.yAxis as EChartOption.YAxis[];
    list.forEach((item, index) => {
       const axisInfo = axisList[index];
       if (
           axisInfo.hasUpdateRange()
       ) {
           axisInfo.resetRangeOfAxis(splitNumber, item);
       }
       return item;
    });
    return copiedOpt;
}

export function getAxisRange(opts: Partial<NEChartsRelate.IAxisRangeOption> & Pick<NEChartsRelate.IAxisRangeOption, "min" | "max">): NEChartsRelate.IAxisRange {
    const rangeOption: NEChartsRelate.IAxisRangeOption = {
        splitNumber: 5,
        scaleFactor: 0.9,
        isReferZero: true,
        ...opts,
    };
    const { splitNumber, scaleFactor, isReferZero } = rangeOption;
    let { min, max } = rangeOption;
    if (isNaN(min)) {
        min = 0;
    }
    if (isNaN(max)) {
        max = min + 1;
    }
    if (min === max) {
        if (min > 0) {
            min = 0;
            max = 2 * max;
        } else if (min < 0) {
            max = 0;
            min = 2 * min;
        } else {
            min = 0;
            max = 1;
        }
    }
    if (min > max) {
        [ min, max ] = [ max, min ];
    }
    if (isReferZero) {
        if (max < 0) {
            max = 0;
        }
        if (min > 0) {
            min = 0;
        }
    }
    let baseInterval = (max - min) / (splitNumber * scaleFactor);
    let lg10 = Math.log10(baseInterval);
    if (lg10 < 0) {
        lg10 = Math.floor(lg10);
    } else {
        lg10 = Math.ceil(lg10);
    }
    let unit = Math.pow(10, lg10);
    let interval: number;
    if (unit < 1) {
        interval = Math.ceil(baseInterval / unit) / (1 / unit);
    } else {
        interval = Math.ceil(baseInterval * unit) / unit;
    }
    if (isReferZero && max === 0) {
        if (unit < 1) {
            min = Math.floor((max - interval * splitNumber) / unit) / (1 / unit);
        } else {
            min = Math.floor((max - interval * splitNumber) * unit) / unit;
        }
    } else {
        if (unit < 1) {
            max = Math.floor((min + interval * splitNumber) / unit) / (1 / unit);
        } else {
            max = Math.floor((min + interval * splitNumber) * unit) / unit;
        }
    }
    return {
        min,
        max,
        splitNumber: rangeOption.splitNumber,
        interval,
    };
}
